package com.fjwt.gz.wxMp.applet;

import cn.hutool.core.map.MapUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fjwt.gz.core.cache.RedisUtil;
import com.fjwt.gz.core.exception.BizException;
import com.fjwt.gz.core.third.interfaces.IAppletService;
import com.fjwt.gz.core.utils.Base64;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信直联小程序
 */
@Slf4j
@Service
public class AppletWxChatService implements IAppletService {

    private static final String OPENID_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
    private static final String PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";
    private static final String QRCODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s";
    private static final String SUBSCRIBE_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s";

    /**
     * 获取微信小程序的openid
     * @param appId
     * @param code
     * @param appSecretKey 微信小程序的appSecret
     * @return
     */
    @Override
    public String getWxchatPayOpenid(String appId, String code, String appSecretKey) {
        CloseableHttpClient httpClient = HttpClients.custom()
                .disableContentCompression().disableAutomaticRetries().build();
        CloseableHttpResponse response = null;
        //String reqUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + appSecretKey + "&js_code=" + code + "&grant_type=authorization_code";
        String reqUrl = String.format(OPENID_URL, appId, appSecretKey, code);
        log.info("请求路径：{}",reqUrl);
        HttpGet httpGet = new HttpGet(reqUrl);
        httpGet.addHeader("Accept", "application/json;charset=utf-8");
        String res = "";
        try {
            response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            res = EntityUtils.toString(entity, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                log.error("链接流关闭失败");
                e.printStackTrace();
            }
        }

        log.info("微信接口获取用户地域小程序返回结果：{}", res);
        Map<String, Object> mapRes = JSONUtil.parseObj(res);
        log.info("微信认证参数：{}", JSON.toJSONString(mapRes));
        if (!mapRes.containsKey("openid")) {
            throw new BizException("登录失败");
        }
        String openid = MapUtil.getStr(mapRes, "openid");

        return openid;
    }

    /**
     * 获取小程序access_token
     * @param appId
     * @param appSecretKey
     * @return
     */
    @Override
    public  String getAccessToken(String appId,String appSecretKey) {

        String value = RedisUtil.getString("ACCESSTOKEN");
        if (value == null || value.equals("")) {
            value = getRefreshToken(appId, appSecretKey);
        }
        if (value == null) return "";
        return value;
    }

    private static String getRefreshToken(String appId, String appSecretKey) {
        long sTime = System.currentTimeMillis() / 1000 ;
        CloseableHttpClient httpClient = HttpClients.custom()
                .disableContentCompression().disableAutomaticRetries().build();
        CloseableHttpResponse response = null;
        String reqUrl = String.format(ACCESS_TOKEN_URL, appId, appSecretKey);
        //HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + appSecretKey);
        HttpGet httpGet = new HttpGet(reqUrl);
        httpGet.addHeader("Accept", "application/json;charset=utf-8");
        String res = "";
        try {
            response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            res = EntityUtils.toString(entity, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                log.error("链接流关闭失败");
                e.printStackTrace();
            }
        }
        Long eTime = System.currentTimeMillis() / 1000 ;
        log.info("获取小程序token调用凭证开始时间：{},结束时间：{},接口调用时间：{}",sTime,eTime,eTime-sTime);
        log.info("微信接口获取access_token返回结果：{}", res);
        Map<String, Object> mapRes = JSONUtil.parseObj(res);

        if (!mapRes.containsKey("access_token")) {
            return null;
        }
        Integer expires_in = MapUtil.getInt(mapRes, "expires_in");
        String accessToken = MapUtils.getString(mapRes, "access_token");
        RedisUtil.setString("ACCESSTOKEN",accessToken,  expires_in-(eTime-sTime));
        return accessToken;
    }

    /**
     * 获取小程序用户手机号
     * @param code
     * @param appId
     * @param appSecretKey
     * @return
     */
   @Override
    public  String getPhoneNumber(String code,String appId,String appSecretKey) {

        Map<String, Object> parms = new HashMap<>();
        parms.put("code", code);
        String accessToken = getAccessToken(appId, appSecretKey);
        String reqUrl = String.format(PHONE_URL, accessToken);
        /*String result= HttpUtil.createPost("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken).contentType("application/json")
                .body(JSON.toJSONString(parms)).execute().body();*/
        String result= HttpUtil.createPost(reqUrl).contentType("application/json")
                .body(JSON.toJSONString(parms)).execute().body();


        Map<String, Object> mapRes = JSONUtil.parseObj(result);
        Integer errcode = MapUtils.getInteger(mapRes, "errcode");
        if (0 != errcode){
            //删除redis中的ACCESSTOKEN缓存
            RedisUtil.del("ACCESSTOKEN");
            throw  new BizException("系统繁忙，请稍后重试");
        }

        Map<String, Object> maps = JSONUtil.parseObj(MapUtils.getString(mapRes, "phone_info"));



        log.info("微信接口获取手机号返回结果：{}", result);
        return MapUtils.getString(maps, "phoneNumber");
    }

    /**
     * 获取小程序二维码
     * @param json scene(场景值，如userId=123) page(小程序页面路径，如pages/index/index)
     * @param appId
     * @param appSecretKey
     */
    @Override
    public String getUnlimitedQRCode(JSONObject json, String appId, String appSecretKey) {
        String accessToken = getAccessToken(appId, appSecretKey);
        /*HttpResponse execute = HttpUtil.createPost("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken).contentType("application/json")
                .body(JSON.toJSONString(json)).execute();*/
        String reqUrl = String.format(QRCODE_URL, accessToken);
        HttpResponse response = HttpUtil.createPost(reqUrl).contentType("application/json")
                .body(JSON.toJSONString(json)).execute();

        // 首先检查Content-Type
        String contentType = response.header("Content-Type");

        // 如果Content-Type表明是JSON，或者无法确定Content-Type，则尝试解析JSON
        if ((contentType != null && contentType.contains("application/json")) || contentType == null) {
            try {
                JSONObject jsonObject = JSONObject.parseObject(response.body());
                // 确认包含错误码字段
                if (jsonObject.containsKey("errcode")) {
                    String errcode = jsonObject.getString("errcode");
                    if ("40001".equals(errcode)) {
                        // access_token失效，重新获取并重试
                        RedisUtil.del("ACCESSTOKEN");
                        String refreshToken = getRefreshToken(appId, appSecretKey);
                        reqUrl = String.format(QRCODE_URL, refreshToken);
                        response = HttpUtil.createPost(reqUrl).contentType("application/json")
                                .body(JSON.toJSONString(json)).execute();
                    }
                }
            } catch (Exception e) {
                // 解析失败，继续处理为图片流
            }
        }
        byte[] bytes = response.bodyBytes();
        String code =  Base64.encodeBase64String(bytes);
        return code;
    }

    /**
     * 小程序订阅消息
     * @param appId
     * @param code
     * @param appSecretKey
     * @param data  模板内容，格式形如{ "phrase3": { "value": "审核通过" }, "name1": { "value": "订阅" }, "date2": { "value": "2019-12-25 09:42" } }
     * @param templateId 订阅消息模板id
     * @param url 跳转页面
     */
    @Override
    public void sendSubscribeMessage(String appId, String code, String appSecretKey,JSONObject data,String templateId,String url)  {
        JSONObject jsonObject = new JSONObject();
        //获取access_token
        String accessToken = getAccessToken(appId, appSecretKey);
        //获取openid
        String openid = getWxchatPayOpenid(appId, code, appSecretKey);
        //组装json数据
        jsonObject.put("touser", openid);
        jsonObject.put("template_id", templateId);
        jsonObject.put("page", url);
        jsonObject.put("data", data);
        String reqUrl = String.format(SUBSCRIBE_MESSAGE_URL, accessToken);
        HttpResponse response = HttpUtil.createPost(reqUrl).contentType("application/json")
                .body(jsonObject.toString()).execute();
                log.info("微信接口发送订阅消息返回结果：{}", response.body());
    }
}
